package dtl

import (
	"encoding/hex"
	"fmt"
	"io"
	"log"
	"strconv"
	"strings"
	"time"
)

type DL64507 struct {
	Start1  byte
	Addr    []byte
	Start2  byte
	Kz      byte
	DataLen byte
	Data    []byte
	Cs      byte
	End     byte
}

const (
	DtlStart1 = 0x68
	DtlStart2 = 0x68
	DtlEnd    = 0x16
)

func (d *DL64507) Parse(bys []byte) bool {
	Numb := len(bys)
	d.Addr = make([]byte, 6)
	d.Data = make([]byte, 0)
	//检验结尾符号
	for i := 0; i < Numb; i++ {
		if Numb-i < 12 {
			return false
		}
		//log.Printf("bys[%d]=%x", i, bys[i])
		if bys[i] != 0x68 {
			continue
		}
		if bys[i+7] != 0x68 {
			continue
		}
		//找到了数据帧头部
		d.Start1 = 0x68
		d.Addr = bys[i+1 : i+7]
		d.Start2 = 0x68
		d.Kz = bys[i+8]
		d.DataLen = bys[i+9]
		if i+10+int(d.DataLen)+1 > Numb {
			continue
		}
		d.Data = bys[i+10 : i+10+int(d.DataLen)]
		d.Cs = bys[i+10+int(d.DataLen)]
		d.End = bys[i+10+int(d.DataLen)+1]
		if d.End != 0x16 {

			continue
		}
		return true
	}
	return false
}
func (d *DL64507) AddrString() string {
	if len(d.Addr) != 6 {
		return ""
	}
	add := make([]byte, 6)
	for i, x := range d.Addr {
		add[6-i-1] = x
	}
	return hex.EncodeToString(add)
}
func (d *DL64507) ParseAddr(id string) bool {
	addr, err := hex.DecodeString(id)
	if err != nil {
		return false
	}
	if len(addr) != 6 {
		return false
	}
	d.Addr = make([]byte, 6)
	for i, x := range addr {
		d.Addr[6-i-1] = x
	}
	return true
}

func (d *DL64507) GetCS(bys []byte) byte {
	cs := byte(0)
	for _, x := range bys {
		cs += x
	}
	return cs
}

func (d *DL64507) ToBytes() []byte {
	d.Start1 = DtlStart1
	d.End = DtlEnd
	d.Start2 = DtlStart2
	d.DataLen = byte(len(d.Data))
	d.End = DtlEnd
	bys := make([]byte, 0)
	bys = append(bys, d.Start1)
	bys = append(bys, d.Addr...)
	bys = append(bys, d.Start2)
	bys = append(bys, d.Kz)
	bys = append(bys, d.DataLen)
	bys = append(bys, d.Data...)
	cs := d.GetCS(bys)
	bys = append(bys, cs)
	bys = append(bys, d.End)
	return bys
}

func (d *DL64507) GetCommand(meterid string, data string, kz byte) (bys []byte, isok bool, err error) {
	bys = make([]byte, 0)
	d.Kz = kz
	if !d.ParseAddr(meterid) {
		return bys, false, nil
	}
	data2, err := String2DtlData(data)
	if err != nil {
		return bys, false, err
	}
	d.Data = data2
	d.DataLen = byte(len(d.Data))
	bys = d.ToBytes()
	return bys, true, nil
}

func String2DtlData(str string) (data []byte, err error) {
	data, err = hex.DecodeString(str)
	if err != nil {
		return data, err
	}
	num := len(data)
	data2 := make([]byte, num)
	for i, x := range data {
		data2[len(data)-i-1] = x + 0x33
	}
	return data2, nil
}
func DtlData2byte(data []byte) (str []byte) {
	num := len(data)
	data2 := make([]byte, num)
	for i, x := range data {
		data2[i] = x - 0x33
	}
	//str = hex.EncodeToString(data2)
	return data2
}
func (d *DL64507) UnpakeData() (zl string, data string, bl string) {
	data2 := DtlData2byte(d.Data)
	if len(data2) < 6 {
		return "", "", ""
	}
	ml := data2[0:4]
	tm1 := make([]byte, 4)
	for i, x := range ml {
		tm1[3-i] = x
	}

	va := data2[4:]
	tm2 := make([]byte, len(va))
	for i, x := range va {
		tm2[len(va)-i-1] = x
	}
	zl = hex.EncodeToString(tm1)
	bl = fmt.Sprintf("%d", tm2[0])

	data = hex.EncodeToString(tm2[1:])
	fmt.Println(len(zl)/2, len(data)/2)
	return
}

func (d *DL64507) GetValue(data string, lenght int, xs float64) (ft []float64) {
	ft = []float64{}
	for i := 0; i < len(data); i += lenght {
		if i+lenght > len(data) {
			break
		}
		a := data[i : i+lenght]
		floatValue, err := strconv.ParseFloat(a, 64)
		if err != nil {
			// 处理错误
			fmt.Println("转换错误:", err)
			return
		}
		ft = append(ft, floatValue/xs)
	}
	return ft
}

func (d *DL64507) GetKvi(Meter *Meter, s io.ReadWriteCloser) (err error) {
	// 打开端口
	// c := serial.OpenOptions{
	// 	PortName:              PortName,
	// 	BaudRate:              2400,
	// 	DataBits:              8,
	// 	StopBits:              1,
	// 	ParityMode:            serial.PARITY_EVEN,
	// 	InterCharacterTimeout: 1000,
	// 	MinimumReadSize:       128,
	// }
	// fmt.Println("打开端口:", c)
	// s, err := serial.Open(c)
	// if err != nil {
	// 	return err
	// }
	// defer s.Close()
	// 获取总功率
	err, v := d.GetMeterComandResult(Meter.MeterAddr, "00010000", s, 8, 100)
	log.Printf("总有功功率:%f %s", v, err)
	if err == nil && len(v) > 0 {
		Meter.PT = v[0]
	}
	time.Sleep(1000)
	// 获取电压
	err, v = d.GetMeterComandResult(Meter.MeterAddr, "0201ff00", s, 4, 10)
	log.Printf("电压:%f %s", v, err)
	if err == nil && len(v) > 2 {
		Meter.UV = v[2]
		Meter.VV = v[1]
		Meter.WV = v[0]
	}
	time.Sleep(1000)
	// 获取电流
	err, v = d.GetMeterComandResult(Meter.MeterAddr, "0202ff00", s, 6, 1000)
	log.Printf("电l流:%f %s", v, err)
	if err == nil && len(v) > 2 {
		Meter.UI = v[2]
		Meter.VI = v[1]
		Meter.WI = v[0]
	}
	time.Sleep(1000)
	// 获取功率因素
	err, v = d.GetMeterComandResult(Meter.MeterAddr, "0206ff00", s, 4, 1000)
	log.Printf("功率因素:%f %s", v, err)
	if err == nil && len(v) > 0 {
		Meter.PF = v[0]
		Meter.Uptime = time.Now().Local().Format("2006-01-02 15:04:05")
	}
	log.Printf("获取电能表数据成功 %#v", Meter)
	return nil

}

func (d *DL64507) GetMeterComandResult(meterid string, comand string, rw io.ReadWriteCloser, lenght int, xs float64) (err error, values []float64) {
	// 发送命令
	err = nil
	values = []float64{}
	cmd, isok, err := d.GetCommand(meterid, comand, 0x11)
	if !isok {
		err = fmt.Errorf("命令错误:%s", err)
	}
	_, err = rw.Write(cmd)
	if err != nil {
		return err, values
	}
	bys := make([]byte, 128)
	n, err := rw.Read(bys)
	if n < 1 {
		return fmt.Errorf("读取数据失败:%s", err), values
	}
	if d.Parse(bys[:n]) {
		zl, da, bl := d.UnpakeData()
		if !strings.Contains(zl, comand) {
			log.Printf("命令错误:%s %s", zl, comand)
		}
		fmt.Println(zl, da, bl)
		ft := d.GetValue(da, lenght, xs)
		return nil, ft
	}
	return fmt.Errorf("解析数据失败:%s", err), values
}

func (d *DL64507) ReadMeterId(Meter *Meter, s io.ReadWriteCloser) (err error) {
	Readidbytes := []byte{0xfe, 0xfe, 0xfe, 0xfe, 0x68, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x68, 0x13, 0x00, 0xDF, 0x16}
	// c := serial.OpenOptions{
	// 	PortName:              PortName,
	// 	BaudRate:              2400,
	// 	DataBits:              8,
	// 	StopBits:              1,
	// 	ParityMode:            serial.PARITY_EVEN,
	// 	InterCharacterTimeout: 1000,
	// 	MinimumReadSize:       128,
	// }
	// fmt.Println("打开端口:", c)
	// s, err := serial.Open(c)
	// if err != nil {
	// 	return err
	// }
	// defer s.Close()
	// 获取总功率
	s.Write(Readidbytes)
	bys := make([]byte, 128)
	n, err := s.Read(bys)
	if n < 1 {
		return fmt.Errorf("读取数据失败:%s", err)
	}
	if d.Parse(bys[:n]) {
		Meter.MeterAddr = d.AddrString()
		Meter.MeterType = "DTL07"
		return nil
	}
	return fmt.Errorf("解析数据失败:%s", err)
}
